package com.adinnet.api.user.service.impl;

import com.adinnet.api.appInform.mapper.AppInformMapper;
import com.adinnet.api.appInform.model.AppInform;
import com.adinnet.api.child.mapper.ChildMapper;
import com.adinnet.api.child.model.vo.ChildResp;
import com.adinnet.api.common.service.async.AsyncHandlerTask;
import com.adinnet.api.user.model.User;
import com.adinnet.api.user.mapper.UserMapper;
import com.adinnet.api.user.service.UserService;
import com.adinnet.common.jpush.PushBean;
import com.adinnet.common.sms.response.SmsSendResponse;
import com.adinnet.common.sms.util.ChuangLanSmsUtil;
import com.adinnet.common.utils.*;
import com.adinnet.core.BizResult;
import com.adinnet.core.JsonResult;
import com.adinnet.core.exception.BizException;
import com.adinnet.core.redis.RedisConstant;
import com.adinnet.core.redis.RedisService;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.List;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author zYshuai
 * @since 2020-12-02
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {


    @Autowired
    private RedisService redisService;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private ChildMapper childMapper;

    @Autowired
    private AppInformMapper appInformMapper;

    @Autowired
    private AsyncHandlerTask asyncHandlerTask;

    /**
     * 获取验证码
     *
     * @param mobile
     * @param type
     */
    @Override
    public boolean sendCode(String mobile, String type) {
        QueryWrapper<User> wrapper =new QueryWrapper<>();
        wrapper.eq("tel_no",mobile).eq("deleted",0);
        User user = userMapper.selectOne(wrapper);
        if (null == user) {
            throw new BizException("请先联系管理员申请账号！");
        }
        if (1 == user.getStatus()) {
            throw new BizException("账号锁定，请联系管理员!");
        }
        if ("1".equals(type)) {
            // 生成4位随机数
            String verifyCode = UUIDUtil.getVerifyCode();

            String msg = "验证码： "+ verifyCode +"，5分钟内有效。请勿向他人泄露。若非本人操作，请忽略本消息。";
            SmsSendResponse smsSendResponse = ChuangLanSmsUtil.sendCommonSms(mobile, msg);
            if (!smsSendResponse.getCode().equals("0")) {
                return false;
            }
            //存储到redis
            String redisKey = RedisConstant.PATIENT_LOGIN_VERIFYCODE + mobile;
            return redisService.set(redisKey, verifyCode, RedisConstant.VERIFYCODE_TIME);
        }
        return false;
    }

    /**
     * 手机号密码登录
     *
     * @param mobile
     * @param pwd
     * @param request
     * @return
     */
    @Override
    public JsonResult login(String mobile, String pwd, HttpServletRequest request, String receiveUserId) {
        JSONObject returnObject = new JSONObject();
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("tel_no", mobile).eq("deleted", 0);
        User user = userMapper.selectOne(wrapper);
        if (null == user) {
            return JsonResult.error("请先联系管理员申请账号！");
        }
        if (1 == user.getStatus()) {
            //账号锁定
            return JsonResult.error("账号锁定，请联系管理员!");
        }
        //体验学员体验周期一个月到期后不能使用app
        if(null!=user.getStudentType()&&user.getStudentType()==2&&null!=user.getLastExperienceTime()){
            Date date = new Date();
            if(date.after(user.getLastExperienceTime())){
                return JsonResult.error("体验周期已过，无法使用应用!");
            }
        }
        if (!pwd.equals(user.getPwd())) {
            //2021-07-27 新增需求app账号密码输入5次错误，账号锁定10分钟，提示msg：当前账号已锁定，请稍等10分钟再试
            if (redisService.exists(RedisConstant.PWD + mobile) && (int) redisService.get(RedisConstant.PWD + mobile) >= 5) {
                //2021-08-05 密码输错逻辑还原
                return JsonResult.ok(1000, "");
                //return JsonResult.error("当前账号已锁定，请稍等10分钟再试!");
            }
            //记录输入错误次数
            if (redisService.exists(RedisConstant.PWD + mobile)) {
                redisService.set(RedisConstant.PWD + mobile, (int) redisService.get(RedisConstant.PWD + mobile) + 1);
            } else {
                redisService.set(RedisConstant.PWD + mobile, 1, RedisConstant.PWD_TIME);
            }
            //密码错误
            return JsonResult.error("密码错误，请重新输入!");
        }
        List<ChildResp> details = childMapper.details(user.getId());
        //首次登录推送消息
        if (StringUtils.isEmpty(user.getToken()) && CollectionUtils.isNotEmpty(details)) {
            pushMsg(receiveUserId, details.get(0).getId(), details.get(0).getSchoolId());
        }
        //若存在密码错误次数则清除，从新计数
        if (redisService.exists(RedisConstant.PWD + mobile)) {
            redisService.remove(RedisConstant.PWD + mobile);
        }
//        //存在则直接登录(便于测试，上线时去除) todo
//        if (StringUtils.isNotEmpty(user.getToken()) && redisService.exists(RedisConstant.PATIENT_LOGIN_KEY + user.getToken())) {
//            if (CollectionUtils.isEmpty(details)) {
//                returnObject.put("childDetails", Lists.newArrayList());
//            }
//            returnObject.put("token", user.getToken());
//            returnObject.put("childDetails", details);
//            return JsonResult.ok().put("data", returnObject);
//        }

        String accessToken = JWTUtil.createJWT(user.getId().toString(), user.getPwd(), user.getTelNo(), RedisConstant.TOKEN_SURVIVE_TIME);
        User updateUser = new User();
        updateUser.setToken(accessToken);
        if (StringUtils.isNotEmpty(receiveUserId)) {
            updateUser.setReceiveUserId(receiveUserId);
        }
        userMapper.update(updateUser, wrapper);
        redisSetToken(StringUtils.isNotEmpty(user.getToken()) ? user.getToken() : "", RedisConstant.PATIENT_LOGIN_KEY + accessToken, user, StringUtils.isNotEmpty(user.getToken()));
        returnObject.put("token", accessToken);

        if (CollectionUtils.isEmpty(details)) {
            returnObject.put("childDetails", Lists.newArrayList());
        } else {
            returnObject.put("childDetails", details);
        }
        return JsonResult.ok().put("data", returnObject);
    }

    //首次登录推送消息
    public void pushMsg(String receiveUserId, Integer childId, Integer schoolId) {
        AppInform inform = new AppInform();
        inform.setChildId(childId);
        inform.setSchoolId(schoolId);
        inform.setTitle("欢迎！");
        inform.setContent("欢迎来到豆豆藤线上小课堂，在这里我们将会为孩子们提供自主学习平台。孩子可以通过重复听读来巩固学习到的知识。\n" +
                "\n" +
                "学习模块分为四个部分：课程视频、课程音频、重点词汇、跟读训练。\n" +
                "同时我们引入了语音识别功能，孩子能根据得分自主纠音，也可记下薄弱音节，寻求老师的帮助。");
        inform.setInformType(1);
        inform.setType(1);
        inform.setReceiveUserId(receiveUserId);
        inform.setPubdate(new Date());
        inform.setType(1);
        appInformMapper.insert(inform);
        if (!StringUtil.isBlank(receiveUserId)) {
            PushBean pushBean = new PushBean();
            pushBean.setAppKey(PropertiesConfig.pushAppKey);
            pushBean.setMasterSecret(PropertiesConfig.pushSecret);
            pushBean.setAlert("欢迎来到豆豆藤线上小课堂，在这里我们将会为孩子们提供自主学习平台。孩子可以通过重复听读来巩固学习到的知识。\\n\" +\n" +
                    "                \"\\n\" +\n" +
                    "                \"学习模块分为四个部分：课程视频、课程音频、重点词汇、跟读训练。\\n\" +\n" +
                    "                \"同时我们引入了语音识别功能，孩子能根据得分自主纠音，也可记下薄弱音节，寻求老师的帮助。");
            pushBean.setTitle("欢迎！");
            pushBean.setExtras(null);
            asyncHandlerTask.sendSystemInform(pushBean, receiveUserId);
        }
    }


    //缓存token
    private void redisSetToken(String oldToken, String redisKey, User user, boolean notEmpty) {
        redisService.set(redisKey, user, RedisConstant.TOKEN_SURVIVE_TIME);
        if (notEmpty) {
            redisService.remove(RedisConstant.PATIENT_LOGIN_KEY + oldToken);
        }
    }

    /**
     * 修改密码/忘记密码
     *
     * @param mobile
     * @param pwd
     * @param code
     * @param request
     * @return
     */
    @Override
    public JsonResult updatePwd(String mobile, String pwd, String code, HttpServletRequest request) {
        boolean exists = redisService.exists(RedisConstant.PATIENT_LOGIN_VERIFYCODE + mobile);
        if (!exists) {
            return JsonResult.error("验证码已过期，请重新获取!");
        }
        String redisVerifyCode = redisService.getString(RedisConstant.PATIENT_LOGIN_VERIFYCODE + mobile);
        if (!code.equals(redisVerifyCode)) {
            return JsonResult.error("验证码错误，请重新输入!");
        }
        //删除验证码缓存
        redisService.remove(RedisConstant.PATIENT_LOGIN_VERIFYCODE + mobile);
        UpdateWrapper<User> wrapper = new UpdateWrapper<>();
        wrapper.eq("tel_no", mobile).eq("deleted", 0);
        User userDetails = userMapper.selectOne(wrapper);
        User user = new User();
        user.setPwd(pwd);
        userMapper.update(user, wrapper);
        //删除token缓存 让用户重新登录
        if (StringUtils.isNotEmpty(userDetails.getToken())) {
            redisService.remove(RedisConstant.PATIENT_LOGIN_KEY + userDetails.getToken());
        }
        if (redisService.exists(RedisConstant.PWD + mobile)) {
            redisService.remove(RedisConstant.PWD + mobile);
        }
        return JsonResult.ok("修改成功!");

    }

    /**
     * 注销
     *
     * @param telNo
     * @param request
     * @return
     */
    @Override
    public JsonResult logoff(String telNo, HttpServletRequest request) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("tel_no", telNo).eq("deleted", 0);
        User userDetails = userMapper.selectOne(wrapper);
        if (null == userDetails) {
            return JsonResult.error("用户不存在");
        }
        User user = new User();
        user.setStatus(1);
        user.setReceiveUserId("");
        userMapper.update(user, wrapper);
        redisService.remove(RedisConstant.PATIENT_LOGIN_KEY + userDetails.getToken());
        return JsonResult.ok("注销成功!");
    }

    /**
     * 退出登录
     *
     * @param request
     * @param response
     * @return
     */
    @Override
    public JsonResult logout(String telNo, HttpServletRequest request, HttpServletResponse response) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("tel_no", telNo).eq("deleted", 0);
        User userDetails = userMapper.selectOne(wrapper);
        if (null == userDetails) {
            return JsonResult.error("用户不存在");
        }
        User user = new User();
        user.setReceiveUserId("");
        userMapper.update(user, wrapper);
        redisService.remove(RedisConstant.PATIENT_LOGIN_KEY + userDetails.getToken());
        return JsonResult.ok("退出成功!");
    }

    /**
     * 校验验证码  zYshuai
     */
    @Override
    public JsonResult checkVerification(String mobile, String code, HttpServletRequest request) {
        boolean exists = redisService.exists(RedisConstant.PATIENT_LOGIN_VERIFYCODE + mobile);
        if (!exists) {
            return JsonResult.error("验证码已过期，请重新获取!");
        }
        String redisVerifyCode = redisService.getString(RedisConstant.PATIENT_LOGIN_VERIFYCODE + mobile);
        if (!code.equals(redisVerifyCode)) {
            return JsonResult.error("验证码错误，请重新输入!");
        }
        return JsonResult.ok("验证码正确!");
    }

    /**
     * @param token:
     * @param request:
     * @Description: 校验Token
     * @author zYshuai
     * @Date: 2020/12/24 13:55
     * @return: com.adinnet.core.JsonResult
     */
    @Override
    public JsonResult checkToken(String token, HttpServletRequest request) {
        boolean existsToken = redisService.exists(RedisConstant.PATIENT_LOGIN_KEY + token);
        if (existsToken) return JsonResult.ok("登陆凭证有效!");
        return JsonResult.ok(401, "登陆凭证无效!");
    }
}
